コンソールで作成した ACM 証明書を、AWS CDK で作成した ALB に適用してカスタムドメインで接続してみた

コンソールで作成した ACM 証明書を、AWS CDK で作成した ALB に適用してカスタムドメインで接続してみた

Clock Icon2024.08.30

こんにちは、製造ビジネステクノロジー部の若槻です。

Application Load Balancer(ALB) では、AWS Certificate Manager(ACM) 証明書を使用することにより、カスタムドメインでの接続や HTTPS 通信に対応可能となります。

https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/introduction.html

今回は、AWS マネジメントコンソールで作成した ACM 証明書を、AWS CDK で作成した ALB に適用してカスタムドメインで接続してみました。

証明書を適用しない ALB の場合

まず最初に ACM 証明書を使わない ALB の場合の動作を確認してみます。

CDK コードは以下の通りです。簡素化のためデフォルトアクションは固定レスポンスを返すようにしています。

lib/cdk-sample-stack.ts
import {
  aws_ec2 as ec2,
  aws_elasticloadbalancingv2 as elbv2,
  Stack,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    /**
     * Application Load Balancer の作成
     */
    const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
      vpc: new ec2.Vpc(this, 'VPC'),
      internetFacing: true,
    });

    /**
     * リスナーの作成
     */
    alb.addListener('Listener', {
      port: 80,
      defaultAction: elbv2.ListenerAction.fixedResponse(200, {
        contentType: 'text/plain',
        messageBody: 'Hello, CDK!',
      }),
    });
  }
}

上記を CDK デプロイして DNS 名にリクエストすると、アクセスできますが、保護されていない http 通信となります。

ALB に証明書を適用してみる

次に、コンソールで作成した ACM 証明書を ALB に適用してみます。

カスタムドメインの Hosted Zone は Route 53 に作成済み

前提として、証明書に使用するドメイン名の Hosted Zone は Route 53 に作成済みです。

コンソールから 証明書をリクエスト

ACM のマネジメントコンソールから証明書のリクエストを開始します。

リクエストするのはパブリック証明書です。

使用するカスタムドメインのドメイン名を指定して、リクエストします。

すると証明書がバリデーション待ちで作成されます。Create records in Route 53 をクリックして Route 53 Hosted Zone へのバリデーション用レコードの作成を開始します。

レコードの作成を完了します。

Hosted Zone にバリデーション用のレコードが作成されました。

証明書のコンソールに戻ると、バリデーションが完了して証明書が発行されていることが確認できます。

作成された証明書の Arn は次項で CDK コードで指定するので控えておきます。

CDK で ALB に証明書を適用

CDK コードで ALB に証明書を適用します。リスナーを HTTPS:443 に変更し、証明書の ARN を指定します。

lib/cdk-sample-stack.ts
import {
  aws_ec2 as ec2,
  aws_elasticloadbalancingv2 as elbv2,
  Stack,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    /**
     * Application Load Balancer の作成
     */
    const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
      vpc: new ec2.Vpc(this, 'VPC'),
      internetFacing: true,
    });

    /**
     * リスナーの作成
     */
    alb.addListener('Listener', {
      port: 443,
      certificates: [
        {
          certificateArn: process.env.CERTIFICATE_ARN || '',
        },
      ],
      defaultAction: elbv2.ListenerAction.fixedResponse(200, {
        contentType: 'text/plain',
        messageBody: 'Hello, CDK!',
      }),
    });
  }
}

CDK Diff で差分を確認すると、証明書が適用され、プロトコルが変更されていることが確認できます。

$ npx cdk diff
Stack CdkSampleStack
Hold on while we create a read-only change set to get a diff with accurate replacement information (use --no-change-set to use a less accurate but faster template-only diff)
Security Group Changes
┌───┬──────────────────────────────┬─────┬──────────┬─────────────────┐
│   │ Group                        │ Dir │ Protocol │ Peer            │
├───┼──────────────────────────────┼─────┼──────────┼─────────────────┤
│ - │ ${ALB/SecurityGroup.GroupId} │ In  │ TCP 80   │ Everyone (IPv4) │
├───┼──────────────────────────────┼─────┼──────────┼─────────────────┤
│ + │ ${ALB/SecurityGroup.GroupId} │ In  │ TCP 443  │ Everyone (IPv4) │
└───┴──────────────────────────────┴─────┴──────────┴─────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Resources
[~] AWS::EC2::SecurityGroup ALB/SecurityGroup ALBSecurityGroup8B8624F8
 └─ [~] SecurityGroupIngress
     └─ @@ -1,9 +1,9 @@
        [ ] [
        [ ]   {
        [ ]     "CidrIp": "0.0.0.0/0",
        [-]     "Description": "Allow from anyone on port 80",
        [-]     "FromPort": 80,
        [+]     "Description": "Allow from anyone on port 443",
        [+]     "FromPort": 443,
        [ ]     "IpProtocol": "tcp",
        [-]     "ToPort": 80
        [+]     "ToPort": 443
        [ ]   }
        [ ] ]
[~] AWS::ElasticLoadBalancingV2::Listener ALB/Listener ALBListener3B99FF85
 ├─ [+] Certificates
 │   └─ [{"CertificateArn":"arn:aws:acm:ap-northeast-1:XXXXXXXXXXXX:certificate/83b506b2-476e-4b27-978a-03ad304ff460"}]
 ├─ [~] Port
 │   ├─ [-] 80
 │   └─ [+] 443
 └─ [~] Protocol
     ├─ [-] HTTP
     └─ [+] HTTPS

✨  Number of stacks with differences: 1

CDK デプロイすると、証明書が設定された HTTPS:443 のリスナーが ALB に作成されました。

コンソールから Alias レコードを登録

証明書を適用しただけではカスタムドメインでの接続はできません。ALB への名前解決をするための DNS レコードの登録が必要です。

Route 53 コンソールから、Hosted Zone に ALB の DNS 名をターゲットとした Alias レコードを作成します。

Alias レコードが登録できました。

動作確認

ドメイン名に https でリクエストしたら ALB に接続できました。

パスパラメーターを付けた場合も https でアクセスできました。

一方でサブドメインはレコードを登録していないので当然接続できません。

ALB の DNS 名に直接接続すると http 接続となる

ここで、ALB の DNS 名に直接接続すると、こちらは http 接続となってしまいました。

サーバーへ非暗号化通信で接続できてしまうためセキュリティ的によろしくないですね。

これは ALB での http:80 から https:443 へのリダイレクト設定により https 接続を強制できます。次回以降で試してみます。

(2024/08/31 追記)DNS 名への接続を https:443 へリダイレクトする設定は見当たらなかったため、DNS 名への http 接続を許可しないようにするためには AWS WAF Web ACL やセキュリティグループなどでブロックする必要がありそうです。

おわりに

コンソールで作成した ACM 証明書を、AWS CDK で作成した ALB に適用してカスタムドメインで接続してみた手順をご紹介しました。

AWS インフラを CDK で IaC 化している環境でも、証明書と DNS レコードはコンソールで用意するパターンは多いと思います。そのような場合に参考にしてみてください。

以上

この記事をシェアする

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.